/*User program on Nachos
  For project 4
*/

/*Author: Yuzhe Wu 4/14*/

#include "create.h"


void main () {
	struct examSheet myExamSheet;
	int myNurseID = -1;
	int myExamID = -1;
	int myXrayID = -1;
	int myDocID = -1;
	int symptonID = -1;
	int tmpi = -1;  /*temporary image taken number*/
	int money = -1;
	
	int index = -1;
	bool debugFlag = true;


	/*Printf("P4DEBUG: I am a Patient,in\n");*/
	doCreate();
	
	/*Get the index*/
	rpcAcquireLock(patientIndexLock);
	index=rpcGetValueMV(patientIndex,0);
	rpcSetValueMV(patientIndex,0,(index+1));
	rpcReleaseLock(patientIndexLock);

	Printf("Adult Patient [%d] has entered the Doctor's Office Waiting Room.\n",index);
	rpcAcquireLock(waitingRoomLock);
	
	if(debugFlag == true) {
		Printf("myDEBUG: patient Acquire waitingRoomLock start!\n");
	}
	
	if (rpcGetValueMV(wrnState,0) == BUSY) {
		rpcSetValueMV(waitingRoomPatientCounter,0,rpcGetValueMV(waitingRoomPatientCounter,0)+1);
		Printf("Adult Patient [%d] gets in line of the Waiting Room Nurse to get registeration form.\n",index);
		rpcWaitCV(waitingRoomLock,patientWaitingWRCV);	
	}
	else {	
		rpcSetValueMV(wrnState,0,BUSY);
	}
	
	rpcReleaseLock(waitingRoomLock);
	
	/*Interaction patient&wrn,Get form*/
	if(debugFlag == true) {
		Printf("myDEBUG: Adult Patient [%d] prepare to get form.\n",index);
	}
	rpcAcquireLock(wrnLock);
	
	rpcSetValueMV(wrnTask,0,GETFORM);
	rpcSetValueMV(patientIDTONurse,0,index);	

	if(debugFlag == true) {
		Printf("myDEBUG: Patient ready to signal wrn!\n");
	}
	
	rpcSignalCV(wrnLock, wrnPatient_NurseCV);
	rpcWaitCV(wrnLock,wrnPatient_NurseCV);
	Printf("[Adult patient/Parent of child patient][%d] gets the form from the Waiting Room Nurse.\n",index);
	
	rpcGetExamSheet(wrnExamSheetEmpty,&myExamSheet);
	if(debugFlag == true) {
		Printf("myDEBUG: Adult Patient [%d] get registeration form.\n",index);
	}
	rpcSignalCV(wrnLock, wrnPatient_NurseCV);
	rpcSetValueMV(wrnTask,0,WRONGTASK);
	rpcReleaseLock(wrnLock);
	
	/*The patient fill out the examSheet*/
	myExamSheet.patientID = index;
	myExamSheet.name = "Patient";
	
	myExamSheet.age = Rand(100);  /*Self define syscall; Random Generate the patient age, Uniform distributed in [0 100]*/
	
	symptonID = Rand(3);
	if(symptonID==0) {
		myExamSheet.symptom = "Pain";
	}
	else if(symptonID==1) {
		myExamSheet.symptom = "Nausea";
	}
	else if(symptonID==2) {
		myExamSheet.symptom = "Hear Alien Voices";
	}
	else {
		Printf("ERROR: Wrong symptom\n");
	}
	
	/*Finish filling out the form,Queuing to give the form*/
	
	if(debugFlag == true) {
		Printf("myDEBUG: patient ready to give the form\n");
	}
	rpcAcquireLock(waitingRoomLock);	
	if (rpcGetValueMV(wrnState,0) == BUSY) {		
		rpcSetValueMV(waitingRoomPatientCounter,0,rpcGetValueMV(waitingRoomPatientCounter,0)+1);
		Printf("Adult Patient [%d] gets in line of the Waiting Room Nurse to submit registeration form.\n",index);
		rpcWaitCV(waitingRoomLock,patientWaitingWRCV);
	}
	else {
		rpcSetValueMV(wrnState,0,BUSY);
	}	
	rpcAcquireLock(wrnLock);
	rpcReleaseLock(waitingRoomLock);
	
	/*Interaction patient&wrn,Give form*/
	rpcSetValueMV(wrnTask,0,GIVEFORM);
	Printf("DEBUG: the wrnExamSheet index is %d.   The patientID is %d\n\n\n\n\n", wrnExamSheet, myExamSheet.patientID);
	rpcSetExamSheet(wrnExamSheet, myExamSheet);
	rpcSignalCV(wrnLock, wrnPatient_NurseCV);
	rpcWaitCV(wrnLock,wrnPatient_NurseCV);
	Printf("[Adult patient/Parent of child patient][%d] submits the filled form to the Waiting Room Nurse.\n",index);
	rpcAcquireLock(sittingRoomLock);
	rpcSetValueMV(wrnTask,0,WRONGTASK);

	if (debugFlag == true) {
		Printf("myDEBUG: Adult Patient [%d] submit the examSheet e.\n",index);
	}
	rpcSignalCV(wrnLock, wrnPatient_NurseCV);
	
	if(debugFlag == true) {
		Printf("myDEBUG: Adult Patient [%d] gets finish the examSheet.\n",index);
	}
	/*Patient interact with nurse*/
	rpcReleaseLock(wrnLock);
	
	if(debugFlag == true) {
		Printf("myDEBUG:Patient[%d]waiting for nurse to come\n", index);
	}
		
	rpcSetValueMV(sittingRoomCounter,0,rpcGetValueMV(sittingRoomCounter,0)+1);
	rpcAcquireLock(testLock);
	rpcReleaseLock(sittingRoomLock);
	rpcWaitCV(testLock,patientWaitingNurseSRCV);
	rpcReleaseLock(testLock);
	
	myNurseID = rpcGetValueMV(nurseIDTOPatientSR,0);
	if(debugFlag == true) {
		Printf("myDEBUG:\n\nPatient [%d] is waken up by Nurse [%d] in waiting Room\n\n", index, myNurseID);
	}
	
	/*Line 647 - line 662 for debug in original doctorOffice.cc*/
	rpcAcquireLock(nurseLock[myNurseID]);
	rpcSignalCV(nurseLock[myNurseID], nursePatientCV[myNurseID]);
	myExamID = rpcGetValueMV(examIDTOPatient,myNurseID);
	
	/*Find the nurse to interaction with!*/
	rpcWaitCV(nurseLock[myNurseID],nursePatientCV[myNurseID]);
   /*Wait for the nurse to wake him up with the proper examRoom index*/
	Printf("[Adult Patient/Parent] [%s%d] is following Nurse [%d] to Examination Room [%d]\n", myExamSheet.name,myExamSheet.patientID,myNurseID,myExamID);
	Printf("[Adult Patient/Parent] [%s%d] has arrived at Examination Room [%d]\n", myExamSheet.name,myExamSheet.patientID,myExamID);
	
	rpcAcquireLock(examRoomLock[myExamID]);
	rpcSignalCV(nurseLock[myNurseID], nursePatientCV[myNurseID]);	
	rpcReleaseLock(nurseLock[myNurseID]);
	
	if(debugFlag == true) {
		Printf("myDEBUG: patient [%s%d] finish interaction with nurse\n", myExamSheet.name,myExamSheet.patientID);
	}
	
	rpcWaitCV(examRoomLock[myExamID],patientWaitingDocCV[myExamID]);
	/*By now, I am waiting in exam room for doctor*/
	
	/*Start interaction doctor & patient*/
	myDocID = rpcGetValueMV(docIDTOPatient,myExamID);
	if(debugFlag == true) {
		Printf("myDEBUG: Adult Patient [%s%d] has interact with Doctor [%d]\n",myExamSheet.name,myExamSheet.patientID,myDocID);
	}
	rpcAcquireLock(docLock[myDocID]);
	rpcReleaseLock(examRoomLock[myExamID]);
	
	rpcSignalCV(docLock[myDocID],docPatientCV[myDocID]);
	rpcWaitCV(docLock[myDocID],docPatientCV[myDocID]);
	
	rpcGetExamSheet(docExamSheet[myDocID], &myExamSheet); /*Get back the ExamSheet From Doc*/
	
	if(index != myExamSheet.patientID){
		Printf("myDEBUG:FATAL ERROR: patient [%d] doctor give me the wrong examsheet with patient id %d\n\n\n\n\n", index, myExamSheet.patientID);
	}
	
	if(debugFlag == true) {
		Printf("myDEBUG: Patient [%s%d] receive the result from doc\n", myExamSheet.name,myExamSheet.patientID);
		Printf("my Patient [%s%d] receive the result from doc\n", myExamSheet.name, myExamSheet.patientID);
	}
	
	if(myExamSheet.needXray == true) {
		Printf("Adult Patient [%s%d] has been informed by Doctor [%d] that he needs an Xray\n", myExamSheet.name,myExamSheet.patientID,myDocID);
	}
	
	if(myExamSheet.needShot == true) {
		Printf("Adult Patient [%s%d] has been informed by Doctor [%d] that he will be administered a shot\n", myExamSheet.name,myExamSheet.patientID,myDocID);
	}
	
	Printf("Adult Patient [%s%d] has been diagnosed by Doctor [%d]\n", myExamSheet.name,myExamSheet.patientID,myDocID);
	
	if(debugFlag == true) {
		Printf("myDEBUG: Adult Patient [%s%d] has finish with Doctor [%d]\n", myExamSheet.name,myExamSheet.patientID,myDocID);
	}
	rpcAcquireLock(examRoomLock[myExamID]);
	rpcSignalCV(docLock[myDocID],docPatientCV[myDocID]);
	rpcReleaseLock(docLock[myDocID]);
	
	if(debugFlag == true) {
		Printf("myDEBUG: Adult Patient [%s%d] waiting in the ER [%d]\n", myExamSheet.name,myExamSheet.patientID,myExamID);
	}
	
	if(myExamSheet.nextDestination == XRAYROOM) {
		Printf("Adult Patient [%d] waits for a Nurse to escort them to the Xray room.\n", myExamSheet.patientID);
		/*Other print for Parent*/
	}
	rpcWaitCV(examRoomLock[myExamID],patientWaitingNurseERCV[myExamID]);	
	rpcReleaseLock(examRoomLock[myExamID]);
	
	/*at exam room, goto exam room to take shot*/
	if(myExamSheet.needShot == true){
		myNurseID = rpcGetValueMV(nurseIDTOPatientER,myExamID);
		Printf("Adult Patient/Parent [%s%d] says, yes I am/He is ready for the shot?.\n", myExamSheet.name, myExamSheet.patientID);
		rpcAcquireLock(nurseLock[myNurseID]);
		rpcSignalCV(nurseLock[myNurseID],nursePatientCV[myNurseID]);    /*Start interacting with patient*/
		rpcAcquireLock(examRoomLock[myExamID]);
		rpcReleaseLock(nurseLock[myNurseID]);
		
		if(myExamSheet.needXray == true) {
			Printf("Adult Patient [%d] waits for a Nurse to escort them to the Xray room.\n", myExamSheet.patientID);
			/*Print for parent*/
		}
		rpcWaitCV(examRoomLock[myExamID],patientWaitingNurseERCV[myExamID]);
		rpcReleaseLock(examRoomLock[myExamID]);		
	}
	
	/*patient at exam room, goto xray wait at Xray room for nurse to take me to exam room 
	  then interact with doctor at exam room,end up waiting nurse in exam room
	*/
	if(myExamSheet.needXray == true){
		/*get information from nurse, and then leave exam room*/
		myXrayID = rpcGetValueMV(xrayIDTOPatient,myExamID);
		if(debugFlag == true) {
			Printf("myDEBUG:Patient my xrayID is %d\n", myXrayID);
		}
		
		rpcAcquireLock(examRoomLock[myExamID]);
		rpcSetValueMV(examState,myExamID,FREE);

		if(debugFlag == true) {
			Printf("myDEBUG:Patient set the exam Room FREE\n");
		}
		
		rpcReleaseLock(examRoomLock[myExamID]);
		rpcAcquireLock(xrayRoomLock[myXrayID]);
		
		if(debugFlag == true) {
			Printf("myDEBUG:PATIENT GONNA TO SIGNAL EXRAY MAN!!\n");
		}
		
		rpcSignalCV(xrayRoomLock[myXrayID],xrayPatientCV[myXrayID]);
	
		/*waiting for the instruction of XRay techinician*/
		rpcWaitCV(xrayRoomLock[myXrayID],xrayPatientCV[myXrayID]);
		
		Printf("[Adult Patient/Parent] [%s%d] gets on the table.\n",myExamSheet.name,myExamSheet.patientID);
		Printf("[Adult Patient/Parent] [%s%d] has been asked to take an Xray.\n",myExamSheet.name,myExamSheet.patientID);
		rpcSignalCV(xrayRoomLock[myXrayID],xrayPatientCV[myXrayID]);
		
		if((myExamSheet.imageNum)>1) {
			for(tmpi=0;tmpi<(myExamSheet.imageNum-1);tmpi++) {
				rpcWaitCV(xrayRoomLock[myXrayID],xrayPatientCV[myXrayID]);
				Printf("[Adult Patient/Parent] [%s%d] moves for the next Xray\n",myExamSheet.name,myExamSheet.patientID);
				rpcSignalCV(xrayRoomLock[myXrayID],xrayPatientCV[myXrayID]);
			}		
		}
		rpcWaitCV(xrayRoomLock[myXrayID],xrayPatientCV[myXrayID]);
		
		if(debugFlag == true) {
			Printf("DEBUG:[Adult Patient/Parent] [%s%d]waits for a Nurse to escort him/her to Exam room.\n",myExamSheet.name,myExamSheet.patientID);
		}
		rpcWaitCV(xrayRoomLock[myXrayID],patientWaitingNurseXRCV[myXrayID]); /*wait for nurse take me to exam room*/
		rpcSignalCV(xrayRoomLock[myXrayID],xrayPatientCV[myXrayID]);
		rpcReleaseLock(xrayRoomLock[myXrayID]);
		
		myNurseID = rpcGetValueMV(nurseIDTOPatientXR,myXrayID);
		myExamID = rpcGetValueMV(examIDTOPatient,myNurseID);
		
		rpcAcquireLock(nurseLock[myNurseID]);
		rpcAcquireLock(examRoomLock[myExamID]);
		rpcSignalCV(nurseLock[myNurseID],nursePatientCV[myNurseID]);
		rpcReleaseLock(nurseLock[myNurseID]);
		rpcWaitCV(examRoomLock[myExamID],patientWaitingDocCV[myExamID]);
		
		/*patient interact with doctor*/
		myDocID = rpcGetValueMV(docIDTOPatient,myExamID);
		rpcAcquireLock(docLock[myDocID]);
		rpcSignalCV(docLock[myDocID],docPatientCV[myDocID]);
		rpcReleaseLock(docLock[myDocID]);
		rpcWaitCV(examRoomLock[myExamID],patientWaitingNurseERCV[myExamID]);
		rpcReleaseLock(examRoomLock[myExamID]);	
	}	/*End of need Xray*/
	
	rpcAcquireLock(examRoomLock[myExamID]);
	rpcSetValueMV(examState,myExamID,FREE);
	rpcReleaseLock(examRoomLock[myExamID]);
	
	rpcAcquireLock(cashierRoomLock);
	Printf("[Adult Patient/Parent][%s%d]enters the queue of cashier\n",myExamSheet.name,myExamSheet.patientID);
	
	/*Start to interact with cashier*/
	if(rpcGetValueMV(cashierState,0) == FREE){
		rpcSetValueMV(cashierState,0,BUSY);
		rpcReleaseLock(cashierRoomLock);
	}
	
	else{		
		rpcSetValueMV(cashierRoomCounter,0,rpcGetValueMV(cashierRoomCounter,0)+1);
		rpcWaitCV(cashierRoomLock,patientWaitingCRCV);
		rpcReleaseLock(cashierRoomLock);
	}

	/*Enter the cahiser room and start interacting*/
	Printf("Adult Patient[%d] has reached cashier.\n", myExamSheet.patientID);
	/*Print for parent*/	
	
	rpcAcquireLock(cashierLock);
	
	if(debugFlag == true) {
		Printf("myDEBUG:Patient [%d] :my name is %s\n", myExamSheet.patientID, myExamSheet.name);
	}
	rpcSetExamSheet(cashierExamSheet, myExamSheet);
	
	Printf("Adult Patient [%d] hands over his examsheet to the cashier\n",myExamSheet.patientID);
	/*Print for parent*/
	rpcSignalCV(cashierLock,cashierPatientCV);
	rpcWaitCV(cashierLock,cashierPatientCV);
	
	
	money=rpcGetValueMV(bill,0);
	Printf("Adult Patient [%d] pays the cashier $ %d\n",myExamSheet.patientID, money);
	/*print for parent*/
	rpcSignalCV(cashierLock,cashierPatientCV);
	rpcWaitCV(cashierLock,cashierPatientCV);
	
	Printf("Adult Patient [%d] receives a receipt from the cashier\n",myExamSheet.patientID);
	rpcSignalCV(cashierLock,cashierPatientCV);
	
	rpcAcquireLock(patientLeftNumLock);
	
	rpcSetValueMV(patientLeftNum,0,rpcGetValueMV(patientLeftNum,0)+1);
	
	if(debugFlag == true) {
		Printf("myDEBUG: The number of patient that leave is %d \n", rpcGetValueMV(patientLeftNum,0));
	}
	
	rpcReleaseLock(patientLeftNumLock);
	
	rpcReleaseLock(cashierLock);
	
	
	Printf("Adult Patient [%d] leaves the doctor office.\n",myExamSheet.patientID);
	/*print for parent*/
	Exit(0);
}